package org.totoro.lambda;

import org.junit.Before;
import org.junit.Test;
import org.totoro.UserVo;
import org.totoro.Users;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * 参考：
 * http://blog.csdn.net/piglite/article/details/53823584
 * http://blog.csdn.net/maosijunzi/article/details/38658095
 * http://blog.csdn.net/weixin_29135773/article/details/54095573
 * <p>
 * <p>
 * Predicate<T>——接收 T 并返回 boolean
 * Consumer<T>——接收 T，不返回值
 * Function<T, R>——接收 T，返回 R
 * Supplier<T>——提供 T 对象（例如工厂），不接收值
 * UnaryOperator<T>——接收 T 对象，返回 T
 * BinaryOperator<T>——接收两个 T，返回 T
 * <p>
 * http://blueskykong.com/2017/05/14/lambda/
 */
public class CollectorTest {

    private List<String> list = new ArrayList<>();

    List<Users> users;

    @Before
    public void load() {
        list.add("张三");
        list.add("李四");
        list.add("王五");
        list.add("赵六");

        users = Arrays.asList(new Users(1, "张三", 18),
                new Users(2, "李四", 30),
                new Users(3, "王五", 20),
                new Users(4, "赵六", 18));

    }

    /**
     * Function<T, R> -T作为输入，返回的R作为输出
     */
    @Test
    public void Function() {

        Function<String, String> function = (x) -> {
            System.out.print(x + ": ");
            return "Function";
        };
        System.out.println(function.apply("hello world"));
    }

    /**
     * Predicate<T> -T作为输入，返回的boolean值作为输出
     */
    @Test
    public void Predicate() {

        Predicate<String> pre = (x) -> {
            System.out.print(x);
            return false;
        };
        System.out.println(": " + pre.test("hello World"));

    }

    /**
     * Consumer<T> - T作为输入，执行某种动作但没有返回值
     */
    @Test
    public void Consumer() {
        Consumer<String> con = (x) -> {
            System.out.println(x);
        };
        con.accept("hello world");
    }


    /**
     * Supplier<T> - 没有任何输入，返回T
     */
    @Test
    public void Supplier() {
        Supplier<String> supp = () -> {
            return "Supplier";
        };
        System.out.println(supp.get());
    }

    /**
     * BinaryOperator<T> -两个T作为输入，返回一个T作为输出，对于“reduce”操作很有用
     */
    @Test
    public void BinaryOperator() {
        BinaryOperator<String> bina = (x, y) -> {
            System.out.print(x + " " + y);
            return "BinaryOperator";
        };
        System.out.println("  " + bina.apply("hello ", "world"));
    }


    /**
     * 分组
     *
     * @see Collectors#groupingBy(Function)
     */
    @Test
    public void groupingBy() {

        users.stream().collect(Collectors.groupingBy(Users::getAge)).forEach((key, value) -> {
            System.out.println(key + "  ---" + value);
        });

    }

    /**
     * 分组,然后取最大的值
     * <p>
     * Function :需要分组的字段
     * <p>
     * Collector：对分组后的集合进行操作
     *
     * @see Collectors#groupingBy(Function, Collector)
     * <p>
     * * @see http://blog.csdn.net/u013291394/article/details/52662761
     * @see http://blog.csdn.net/piglite/article/details/53823584
     */
    @Test
    public void groupingByMax() {

        //分组后去最大值
        Map<Integer, Optional<Users>> collect = users.stream().collect(Collectors.groupingBy(Users::getAge, Collectors.maxBy(Comparator.comparing(Users::getId))));

        //分组后去最小值
        Map<Integer, Optional<Users>> collect2 = users.stream().collect(Collectors.groupingBy(Users::getAge, Collectors.minBy(Comparator.comparing(Users::getId))));

        collect.forEach((key, value) -> {
            System.out.println("key " + key + "          " + "value : " + value);
        });


        System.out.println("---------------------");

        collect2.forEach((key, value) -> {
            System.out.println("key " + key + "          " + "value : " + value);
        });

    }


    /**
     * 分组，返回指定信息
     *
     * @see Collectors#groupingBy(Function, Supplier, Collector)
     * <p>
     * <p>
     * 把A对象转换为B对象返回
     * @see Collectors#mapping(Function, Collector)
     */
    @Test
    public void mapping() {

        Map<Integer, List<String>> collect = users.stream().collect(Collectors.groupingBy(Users::getAge, Collectors.mapping(Users::getName, Collectors.toList())));

        //   Map<Integer, List<Object>> collect = users.stream().collect(Collectors.groupingBy(Users::getAge, Collectors.mapping(item ->{ return Arrays.asList(item); }, Collectors.toList())));

        collect.forEach((key, value) -> {
            System.out.println("key : " + key + "value :" + value);
        });
    }


    /**
     * 排序 、多条件排序,注意事项，排序的字段不能为空
     */
    @Test
    public void comparator() {

        /**
         *
         * 手动排序
         * 1、年龄倒叙
         * 2、id 升序
         *
         */
        Comparator<Users> usersComparator = Comparator.comparing(Users::getAge, (o1, o2) -> {
            // 倒叙
            return o1.compareTo(o2);
        }).thenComparing(Users::getId, (o1, o2) -> {
            // 升序
            return o1.compareTo(o2);
        });
        List<Users> collect = users.stream().sorted(usersComparator).collect(Collectors.toList());

        collect.forEach(item -> {
            System.out.println(item);
        });

        System.out.println("----------------------------------");

        /**
         *
         * Comparator.naturalOrder 倒叙
         *
         * 1、年龄倒叙
         * 2、id 升序
         *
         */
        Comparator<Users> usersComparator2 = Comparator.comparing(Users::getAge, Comparator.naturalOrder()).thenComparing(Users::getId, Integer::compareTo);
        List<Users> collect2 = users.stream().sorted(usersComparator2).collect(Collectors.toList());

        collect2.forEach(item -> {
            System.out.println(item);
        });

    }


    /**
     * 收集器
     * <p>
     * List<Map> personToMap = people.collect(ArrayList::new, (list, p) -> {
     * Mapmap = new HashMap<>();
     * map.put("name", p.name);
     * map.put("age", p.age);
     * list.add(map);
     * }, List::addAll);
     */
    public void collect() {

        ArrayList<UserVo> collect = users.stream().collect(ArrayList<UserVo>::new, (list, p) -> {

        }, List::addAll);

    }

    public void collect2(){

    }


}
